<template>
  <div class="x-diy-column">
    <x-button :size="buttonSize" :loading="loading" @click="handleVisible">{{ title }}</x-button>
    <x-drawer v-model:visible="visible" :title="title" width="610px">
      <div style="display: flex; height: 100%">
        <div style="width: 350px">
          <n-checkbox-group v-if="visible" v-model:value="checkedList" size="small" @update:value="onChangeChecked">
            <div class="x-diy-column-list">
              <div v-for="(item, index) in list" :key="index" class="item">
                <n-checkbox :value="item.value" :disabled="index < min" :label="item.label" />
              </div>
            </div>
          </n-checkbox-group>
        </div>
        <div class="x-diy-column-body" style="flex: 1; background-color: #fafbfc; padding: 18px">
          <div class="header">
            <div class="title">
              <span style="flex: 1">已选指标</span>
              <x-button style="float: right" :text="true" type="primary" size="small" @click="handleReset"
                >清除</x-button
              >
            </div>
            <div v-for="(item, index) in disabledList" :key="index" class="spaui-columns-list-item">
              <n-icon style="visibility: hidden"> <MenuOutlined size="14" /></n-icon>
              <span style="flex: 1; margin: 0 8px">{{ findLabel(item) }}</span>
            </div>
          </div>
          <div class="spaui-hr-sect">以上指标将横向固定</div>
          <n-scrollbar style="height: calc(100% - 100px)" trigger="none">
            <div class="x-draggable-content">
              <draggable
                v-model="sortCheckedList"
                :group="{ name: 'name', pull: false, put: false }"
                v-bind="dragOptions"
                item-key="id"
              >
                <template #item="{ element }">
                  <div
                    v-if="!disabledList.includes(element) && findLabel(element)"
                    :key="element"
                    class="spaui-columns-list-item"
                    style="cursor: pointer"
                  >
                    <n-icon> <MenuOutlined size="14" /></n-icon>
                    <span style="flex: 1; margin: 0 8px">{{ findLabel(element) }}</span>
                    <n-icon v-if="isDelete(element)" class="close" @click="handleClose(element)">
                      <CloseOutlined size="14" />
                    </n-icon>
                  </div>
                </template>
              </draggable>
            </div>
          </n-scrollbar>
        </div>
      </div>
      <template #footer>
        <x-button @click="handleCancelDrawer">取消</x-button>
        <x-button type="primary" @click="handleSubmit">保存</x-button>
      </template>
    </x-drawer>
  </div>
</template>

<script lang="ts">
  import { computed, defineComponent, reactive, toRefs, watch } from 'vue'
  import { NCheckboxGroup, NCheckbox, NIcon, NScrollbar } from 'naive-ui'
  import { MenuOutlined, CloseOutlined } from '@vicons/antd'
  import { XButton, XDrawer } from '@/components'
  import { useStore } from '@/store'
  import { useDictionary } from '@/hooks'
  import draggable from 'vuedraggable'

  export default defineComponent({
    name: 'XDiyColumn',
    components: {
      NCheckboxGroup,
      NCheckbox,
      XDrawer,
      XButton,
      draggable,
      NIcon,
      NScrollbar,
      MenuOutlined,
      CloseOutlined
    },
    props: {
      value: {
        type: [Array, Object],
        default: () => []
      },
      // 必填，缓存时需要使用
      name: {
        type: String,
        default: 'name',
        required: true
      },
      title: {
        type: String,
        default: '自定义列'
      },
      min: {
        type: Number,
        default: 4
      },
      // 使用api
      api: {
        type: String,
        default: ''
      },
      // 使用字典
      isDictionary: {
        type: Boolean,
        default: false
      },
      // 直接使用数据
      data: {
        type: Array,
        default: () => []
      },
      // 默认选中值
      defaultValue: {
        type: Array,
        default: () => []
      },
      // 按钮大小
      buttonSize: {
        type: String,
        default: 'medium'
      }
    },
    emits: ['update:value'],
    setup($props, { emit: $emit }) {
      const $dictionary = useDictionary()
      const $store = useStore()
      const $state = reactive({
        ...toRefs($props),
        loading: false,
        visible: false,
        // 字典
        dictionary: computed(() => $store.getters.dictionary),
        localName: computed(() => `LOCAL-DIY-COLUMN-${$props.name}`),
        list: [],
        checkedList: [],
        oldVal: [],
        // 排序
        sortCheckedList: [],
        dragOptions: computed(() => {
          return {
            animation: 200,
            disabled: false,
            ghostClass: 'ghost'
          }
        }),
        // 不可选中
        disabledList: []
      })
      const isDelete = (val: any) => {
        let arr: never[] = []
        for (let i = 0; i < $props.min; i++) {
          arr.push($state.list[i]?.value)
        }
        return !arr?.includes(val)
      }

      const initList = async () => {
        let localValue = localStorage.getItem($state.localName)
        if (!localValue && $props.defaultValue.length) {
          localValue = JSON.stringify($props.defaultValue)
        }
        $state.loading = true
        if ($props.isDictionary) {
          await $dictionary.get($props.name)
          $state.list = $state.dictionary[$props.name] || []
        } else if ($props.api) {
          const { data } = await $store.dispatch($props.api)
          $state.list = data || []
        } else {
          $state.list = $props.data || []
        }
        $state.loading = false
        // 最少选中数据
        if ($props.min && $state.list.length) {
          const len = localValue ? $props.min : $state.list.length
          for (let i = 0; i < len; i++) {
            $state.checkedList.push($state.list[i].value)
          }
        }
        // 处理缓存数据
        if (localValue) {
          try {
            const arr = JSON.parse(localValue)
            if (Object.prototype.toString.call(arr) === '[object Array]') {
              arr.forEach((item: string) => {
                if (!$state.checkedList.some((s) => s === item)) {
                  $state.checkedList.push(item)
                }
              })
            }
          } catch (e) {
            console.warn('处理缓存数据错误 ', e)
          }
        }
        const newDisabledList = []
        for (let i = 0; i < $state.min; i++) {
          newDisabledList.push($state.list[i].value)
        }
        $state.disabledList = newDisabledList
        $state.oldVal = JSON.parse(JSON.stringify($state.checkedList))
        $state.sortCheckedList = JSON.parse(JSON.stringify($state.checkedList))
        // 初始化完成
        handleSubmit()
      }
      initList()

      // watch
      watch(
        () => $props.name,
        () => {
          initList()
        }
      )
      watch(
        () => $state.visible,
        () => {
          // 关闭抽屉时，重置数据
          $state.checkedList = $state.oldVal
          $state.sortCheckedList = $state.oldVal
        }
      )

      const handleVisible = () => {
        $state.visible = true
      }

      const handleCancelDrawer = () => {
        $state.visible = false
      }

      const handleReset = () => {
        $state.checkedList = $state.checkedList.filter((item, index) => {
          return index < $props.min
        })
        $state.sortCheckedList = $state.checkedList
      }

      const onChangeChecked = () => {
        $state.sortCheckedList = JSON.parse(JSON.stringify($state.checkedList))
      }

      const findLabel = (val: any) => {
        for (let i = 0; i < $state.list.length; i++) {
          if ($state.list[i].value === val) {
            return $state.list[i].label
          }
        }
      }

      const handleClose = (val: any) => {
        $state.checkedList = $state.checkedList.filter((item) => item !== val)
        $state.sortCheckedList = $state.sortCheckedList.filter((item) => item !== val)
      }

      const handleSubmit = () => {
        // 缓存至本地
        // localStorage.setItem($state.localName, JSON.stringify($state.checkedList))
        localStorage.setItem($state.localName, JSON.stringify($state.sortCheckedList))
        // console.log(11, $state.checkedList)
        $state.oldVal = $state.sortCheckedList
        // 排序后的值
        $emit('update:value', $state.sortCheckedList)
        // $emit('update:value', $state.checkedList)
        $state.visible = false
      }

      return {
        ...toRefs($state),
        handleVisible,
        handleSubmit,
        handleCancelDrawer,
        isDelete,
        findLabel,
        handleReset,
        onChangeChecked,
        handleClose
      }
    }
  })
</script>

<style lang="scss" scoped>
  .x-diy-column-body {
    .header {
      background: #fff;
      .title {
        display: flex;
        padding: 10px;
        align-items: center;
      }
    }
  }
  .x-diy-column-list {
    display: flex;
    flex-wrap: wrap;
    .item {
      width: 150px;
      padding: 5px;
    }
  }
  .spaui-hr-sect {
    display: flex;
    padding: 5px 0;
    flex-basis: 100%;
    align-items: center;
    color: #939599;
    font-size: 12px;
  }
  .spaui-hr-sect::after,
  .spaui-hr-sect::before {
    content: '';
    flex-grow: 1;
    background: #edeff2;
    height: 1px;
    font-size: 0;
    line-height: 0;
  }
  .spaui-hr-sect::before {
    margin: 0 16px 0 0;
  }
  .spaui-hr-sect::after {
    margin: 0 0 0 16px;
  }
  .spaui-columns-list-item {
    display: flex;
    align-items: center;
    padding: 10px 15px;
    background: #fff;
    border-top: 1px solid #edeff2;
    .close {
      visibility: hidden;
    }
  }
  .spaui-columns-list-item:hover {
    .close {
      visibility: visible;
    }
  }
  .spaui-columns-list-item:first-child {
    border-top: none;
    border-top-left-radius: 4px;
    border-top-right-radius: 4px;
  }
</style>
